package ro.cityprojects.adminloc.dao;

import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate3.HibernateQueryException;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import ro.cityprojects.adminloc.entities.BaseEntity;

import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * The ParentDAO for all the classes
 *
 * @author bogdan.solga
 *
 * Date: 14.06.2013, time: 13:43
 */
@Repository
public abstract class BaseDAO<PK extends Serializable, Entity extends BaseEntity> {

    protected HibernateTemplate hibernateTemplate;

    @Autowired
    public void setAdminLocSessionFactory(@Qualifier("adminLocSessionFactory") SessionFactory adminLocSessionFactory) {
        hibernateTemplate = new HibernateTemplate(adminLocSessionFactory);
    }

    protected void saveEntity(Entity entity) {
        Assert.notNull(entity, "Invalid / null entity");

        hibernateTemplate.save(entity);
        hibernateTemplate.flush();
    }

    protected Entity get(Class<Entity> entityClass, PK primaryKey) {
        Assert.notNull(primaryKey, "Invalid / null primary key");

        return hibernateTemplate.get(entityClass, primaryKey);
    }

    @SuppressWarnings("unchecked")
    protected Set<Entity> getAll(String filterName, String filterValue, Class<Entity> entityClass) {
        List<Entity> retrievedEntities;
        final String className = entityClass.getSimpleName();

        if (StringUtils.isEmpty(filterName)) {
            retrievedEntities = hibernateTemplate.loadAll(entityClass);

            Assert.notEmpty(retrievedEntities, "There are no '" + className + "'");
        } else {
            DetachedCriteria criteria = DetachedCriteria.forClass(entityClass);

            try {
                Integer value;
                try {
                    value = Integer.parseInt(filterValue);
                    criteria.add(Restrictions.eq(filterName, value));
                } catch (NumberFormatException x) {
                    criteria.add(Restrictions.eq(filterName, filterValue));
                }

                retrievedEntities = hibernateTemplate.findByCriteria(criteria);
            } catch (HibernateQueryException hqe) {
                throw new IllegalArgumentException("Cannot filter '" + className.toLowerCase() + "' by '" + filterName + "'");
            }

            Assert.notEmpty(retrievedEntities, "There are no '" + className.toLowerCase() + "s' with the '" + filterName + "' '" + filterValue + "'");
        }

        Set<Entity> entities = new HashSet<Entity>();
        for (Entity retrievedEntity : retrievedEntities) {
            entities.add(retrievedEntity);
        }

        return entities;
    }

    protected void updateEntity(Entity entity) {
        Assert.notNull(entity, "Null entity");

        hibernateTemplate.update(entity);
    }

    protected void deleteEntity(Class<Entity> entityClass, PK primaryKey) {
        Assert.notNull(primaryKey, "Null primaryKey");

        Entity entity = hibernateTemplate.load(entityClass, primaryKey);

        assertNotNull(entity, entityClass, primaryKey);

        hibernateTemplate.delete(entity);
        hibernateTemplate.flush();
    }

    private void assertNotNull(Entity entity, Class<Entity> entityClass, PK primaryKey) {
        Assert.notNull(entity, "There is no '" + entityClass.getSimpleName() + "' with the primary key '" + primaryKey + "'");
    }
}
